#include "core_headers.hpp"

#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
public:
	Buffer()
		: _write_idx(0), _read_idx(0), _buffer(BUFFER_DEFAULT_SIZE)
	{
	}
	// ======================== 对外接口（业务流程：写入并推进、读取并弹出等） ========================
	// 写入位置地址
	char *WritePosition()
	{
		return Begin() + _write_idx;
	}
	// 读取位置地址
	char *ReadPosition()
	{
		return Begin() + _read_idx;
	}
	// 可读数据大小
	uint64_t ReadableSize()
	{
		return _write_idx - _read_idx;
	}
	// 写入数据并压入
	void WriteAndPush(const void *data, uint64_t len)
	{
		if (data == nullptr || len == 0)
		{
			return;
		}
		Write(data, len);
		MoveWriteOffset(len);
	}
	// 写入字符串数据并压入
	void WriteStringAndPush(const std::string &data)
	{
		WriteString(data);
		MoveWriteOffset(data.size());
	}
	// 写入buffer类数据并压入
	void WriteBufferAndPush(Buffer &data)
	{
		WriteBuffer(data);
		MoveWriteOffset(data.ReadableSize());
	}
	// 读取数据并弹出
	void ReadAndPop(void *buff, uint64_t len)
	{
		Read(buff, len);
		MoveReadOffset(len);
	}
	// 读取字符串数据并弹出
	std::string ReadStringAndPop(uint64_t len)
	{
		assert(len <= ReadableSize()); // 读取数据大小必须小于可读数据大小
		std::string str = ReadString(len);
		MoveReadOffset(len);
		return str;
	}

	// 获取一行缓冲区数据并弹出
	std::string GetLineBufferAndPop()
	{
		std::string str = GetLineBuffer();
		MoveReadOffset(str.size());
		return str;
	}
	// 清空缓冲区
	void Clear()
	{
		_write_idx = 0;
		_read_idx = 0;
	}
	// ======================== 偏移操作（修改读写偏移，依赖空间计算） ========================
	// 读偏移量向后移动
	void MoveReadOffset(uint64_t len)
	{
		// 读向后偏移大小必须小于可读数据大小
		assert(len <= ReadableSize());
		_read_idx += len;
	}
	// 写偏移量向后移动
	void MoveWriteOffset(uint64_t len)
	{
		// 写向后移动偏移大小必须小于后面空闲大小
		assert(len <= TailIdleSize());
		_write_idx += len;
	}

private:
	// ======================== 底层工具函数（纯辅助，不涉及业务） ========================
	char *Begin()
	{
		return &*_buffer.begin();
	}
	// ======================== 空间计算工具（基于工具函数，计算空闲/可读空间） ========================
	// 末尾剩余空间大小
	uint64_t TailIdleSize()
	{
		return _buffer.size() - _write_idx;
	}
	// 起始剩余空间大小
	uint64_t HeadIdleSize()
	{
		return _read_idx;
	}
	// ======================== 核心逻辑（空间确保、实际读写） ========================
	// 确保写入空间足够，末尾剩余空间大小加上起始空间剩余大小
	void EnsureWriteSpace(uint64_t len)
	{
		if (len < TailIdleSize()) // 末尾空间足够
		{
			return;
		}
		else if (len <= TailIdleSize() + HeadIdleSize()) // 末尾空闲空间不够，则判断加上起始位置的空闲空间大小是否足够, 够了就将数据移动到起始位置
		{
			// 移动数据到最开始
			uint64_t res = ReadableSize();						 // 保存当前可读数据大小，后边方便修改偏移量
			std::copy(ReadPosition(), WritePosition(), Begin()); // 把可读数据拷贝到起始位置
			_read_idx = 0;										 // 读偏移量归零
			_write_idx = res;									 // 将写位置置为可读数据大小， 因为当前的可读数据大小就是写偏移量
		}
		else // //总体空间不够，则需要扩容，不移动数据，直接给写偏移之后扩容足够空间即可
		{
			// uint64_t newcapacity = std::max(_buffer.size() * 2, _write_idx + len);
			_buffer.resize(_write_idx + len); // 扩容
			INF_LOG("resize: %ld", _write_idx + len);
		}
	}
	// 写入数据
	void Write(const void *data, uint64_t len)
	{
		if (data == nullptr)
		{
			return;
		}
		EnsureWriteSpace(len);
		const char *da = (const char *)data;
		std::copy(da, da + len, WritePosition());
	}
	// 读取数据
	void Read(void *buff, uint64_t len)
	{
		assert(len <= ReadableSize()); // 读取数据大小必须小于可读数据大小
		std::copy(ReadPosition(), ReadPosition() + len, (char *)buff);
	}
	// ======================== 业务适配（基于核心逻辑，封装字符串、Buffer 读写） ========================
	// 写入字符串数据
	void WriteString(const std::string &data)
	{
		return Write(data.c_str(), data.size());
	}
	// 写入buffer类数据
	void WriteBuffer(Buffer &data)
	{
		return Write(data.ReadPosition(), data.ReadableSize());
	}
	// 读取字符串数据
	std::string ReadString(uint64_t len)
	{
		assert(len <= ReadableSize()); // 读取数据大小必须小于可读数据大小
		std::string str;
		str.resize(len);
		Read(&str[0], len);
		return str;
	}
	// 查找一行数据的结尾\n
	char *FindCRLF()
	{
		char *f = (char *)memchr(ReadPosition(), '\n', ReadableSize());
		return f;
	}
	// 获取一行缓冲区数据
	std::string GetLineBuffer()
	{
		char *pos = FindCRLF();
		if (pos == nullptr)
			return "";
		return ReadString(pos - ReadPosition() + 1); // 要把\n取出来 ,不然下次取一行数据为空
	}

private:
	std::vector<char> _buffer; // 缓冲区
	uint64_t _read_idx;		   // 读偏移量
	uint64_t _write_idx;	   // 写偏移量
};